
#ifndef _THREAD_H__INCLUDED_
#define _THREAD_H__INCLUDED_

namespace nebula { namespace utility {

class Thread;
class ThreadImpl;

class ThreadDetail
{
public:
	typedef void (*ThreadProc)(void*);

public:
	ThreadDetail(ThreadProc thread_proc, void* parameter);
	~ThreadDetail();


	int start();
	int join();
	int start_in_background(Thread*);

private:
	ThreadDetail(const ThreadDetail &thread); // not implemented
	ThreadDetail& operator= (const ThreadDetail& thread); // not implemented

private:
	ThreadImpl *pThread;
};

namespace this_thread {
	void sleep(int ms);
	int get_id();
};

}} // end of nebula::utility

#include "TemplateImpl/ThreadImpl.h"

namespace nebula { namespace utility {

class Thread
{
public:
	Thread()
	{
	}

	Thread(const Thread& _right) :
		_impl(_right._impl)
	{
	}

	const Thread& operator=(const Thread& _right)
	{
		_impl = _right._impl;
		return *this;
	}

	bool operator==(const Thread& _right)
	{
		return _impl == _right._impl;
	}

	//////////////////////////////////////////////////////////////////////////
	template<typename obj_type, typename ret_type>
	explicit Thread(obj_type* obj, ret_type (obj_type::*func)()) :
		_impl(make_thread_impl(make_mem_func(obj, func)))
	{
	}

	template<typename obj_type, typename ret_type, typename p1>
	explicit Thread(obj_type* obj, ret_type (obj_type::*func)(p1), p1 _p1) :
		_impl(make_thread_impl(make_mem_func(obj, func, _p1)))
	{
	}

	template<typename obj_type, typename ret_type, typename p1, typename p2>
	explicit Thread(obj_type* obj, ret_type (obj_type::*func)(p1, p2), p1 _p1, p2 _p2) :
		_impl(make_thread_impl(make_mem_func(obj, func, _p1, _p2)))
	{
	}

	//////////////////////////////////////////////////////////////////////////

	template<typename proc>
	explicit Thread(proc thread_proc) :
		_impl(make_thread_impl(proc_binder<proc>(thread_proc)))
	{
	}

	template<typename proc,
		typename p1
	>
	explicit Thread(proc thread_proc, p1 _p1) :
		_impl(make_thread_impl(proc_binder_1<proc, p1>(thread_proc, _p1)))
	{
	}

	template<typename proc,
		typename p1, typename p2
	>
	explicit Thread(proc thread_proc, p1 _p1, p2 _p2) :
		_impl(make_thread_impl(proc_binder_2<proc, p1, p2>(thread_proc, _p1, _p2)))
	{
	}

	template<typename proc,
		typename p1, typename p2, typename p3
	>
	explicit Thread(proc thread_proc, p1 _p1, p2 _p2, p3 _p3) :
		_impl(make_thread_impl(proc_binder_3<proc, p1, p2, p3>(thread_proc, _p1, _p2, _p3)))
	{
	}

	template<typename proc,
		typename p1, typename p2, typename p3, typename p4
	>
	explicit Thread(proc thread_proc, p1 _p1, p2 _p2, p3 _p3, p4 _p4) :
		_impl(make_thread_impl(proc_binder_4<proc, p1, p2, p3, p4>(thread_proc, _p1, _p2, _p3, _p4)))
	{
	}

public:
	int start() {
		return _impl->start();
	}

	int join() {
		return _impl->join();
	}

	// Start the thread in background, the Thread object should allocated
	// in heap (by new), and the Thread object will automatically deleted
	// by the thread itself after the thread is finished running
	//
	// Attempted to implement operation 'detach' but failed...
	int start_in_background() {
		return _impl->start_in_background(this);
	}

private:
	ref_ptr<thread_impl_base> _impl;
};

}} // namespace nebula::utility

#endif // _THREAD_H__INCLUDED_

